package com.allscore.batch.test.config;

import com.allscore.batch.test.entity.Product;
import com.allscore.batch.test.handler.CsvFileReader;
import com.allscore.batch.test.handler.CsvItemProcessor;
import com.allscore.batch.test.handler.CsvJPAWriter;
import com.allscore.batch.test.handler.CsvListener;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.retry.policy.NeverRetryPolicy;
import org.springframework.transaction.PlatformTransactionManager;

/**
 * 批处理任务配置
 */
@Configuration
@EnableBatchProcessing
public class CSVFileConfig {
	
	//----------------------------CSV文件批处理任务 BEGIN--------------------------------------
	
	//异步执行器，配置步骤时和异步ItemProcessor实现
	@Bean(name="csv2DBSimpleAsyncTaskExecutor")
	public SimpleAsyncTaskExecutor csv2DBSimpleAsyncTaskExecutor() {
		return new SimpleAsyncTaskExecutor();
	}
	
	
	@Autowired
	CsvFileReader csvFileReader;//读取CSV文件输入，继承自FlatFileItemReader<T>
	
	@Autowired
	CsvItemProcessor csvItemProcessor;//csv数据自定义转换，实现ItemProcessor<I,O>接口
	
//	@Autowired
//	CsvJDBCWriter csvJDBCWriter;//csv数据转换后输出，继承JdbcBatchItemWriter<T>
	
	@Autowired
	CsvJPAWriter csvJPAWriter;//用框架内的JPA方式自定义输出，实现ItemWriter<T>接口
	
	@Autowired
	CsvListener csvListener;//csv批处理任务执行前后监听
	
    
    /**
     * 步骤配置：读取csv数据转换后输出到jdbc保存到数据库
     * *********多数据源的情况***********
     * PlatformTransactionManager 需要指定是来自于哪个数据源的事务管理器 如 指定 @Autowired @Qualifier("mercTransactionManager") 
     */
    @Bean  
    public Step initDataStep(StepBuilderFactory stepBuilderFactory, PlatformTransactionManager transactionManager,
    		@Qualifier("csv2DBSimpleAsyncTaskExecutor")SimpleAsyncTaskExecutor csv2DBSimpleAsyncTaskExecutor
    		){
    	String stepName = "initData";
        return stepBuilderFactory.get(stepName)
        		.<Product, Product> chunk(666)//一次读取666条,如果reader是分页的，这里要小于一页的行数
        		.reader(csvFileReader)//配置输入reader
        		.processor(csvItemProcessor)//配置中间数据转换器
        		.writer(csvJPAWriter)//配置输出writer
        		.faultTolerant()//高级设置↓↓↓
//				.retry(Exception.class)//哪个异常需要重试
//				.noRetry(Exception.class)//不需要重试的异常
//				.retryLimit(0)//重试次数
        		.retryPolicy(new NeverRetryPolicy())//永不重试
//        		.skip(Exception.class)//跳过一切异常， 所有异常继承自Exception
//				.noSkip(RamboRunTimeException.class)//不跳过的异常
//				.skipLimit(1)//最大跳过次数
        		.skipPolicy(new AlwaysSkipItemSkipPolicy())//跳过的策略：任意搞事情况都跳
        		.taskExecutor( csv2DBSimpleAsyncTaskExecutor )//默认并发方式，基本异步执行器
        		.throttleLimit(10)//并发数，小于数据源可用的连接，最小4
        		.transactionManager(transactionManager)
        		.build();
    }
    
    /**
     * 配置任务：读取csv文件并保存到数据库
     * 这个方法名会默认为bean的key，不要重复了，重复了就没法在外面@Autowired获取bean
     */
    @Bean
    public Job csv2DB(JobBuilderFactory jobs, @Qualifier("initDataStep")Step initDataStep) {
    	String jobName = "job_csv2db";
        return jobs.get(jobName).incrementer(new RunIdIncrementer())
        		.listener(csvListener)//配置监听器
        		.flow(initDataStep)//配置第一步骤
//        		.next(step)//配置下个步骤
        		.end().build();  
    }
    
	//----------------------------CSV文件批处理任务 END----------------------------------------
	
}
